Repository navigation
docs(api): document exact /status schema separating process vs data health (#273) - #533
Conversation
fdf32b5 to
84a8e2c
Compare
84a8e2c to
5ca617d
Compare
…loses #273) `/status` now reports `status`, `health.process`, `health.data`, a `process` block (uptime, heap) and a `data` block (ledger, lag, `isStale`), keeps the old top-level fields so existing consumers are unaffected, returns a 200 with `status: "degraded"` when ingest lag passes 300s, and a 503 with `pagingCondition: "DATABASE_DOWN"` when Postgres fails — which is the paging threshold the issue asked for. openapi.yaml/json, the TS client and the README monitoring examples are updated together. Two fixes on top of the contribution. 1. **The 503 body returned the Postgres driver's own message on a public, unauthenticated route.** `error: err?.message || 'Database query failed'`, on the most-polled endpoint Lens has. A pg connection failure puts the host, the user and sometimes the entire connection string into that message — Lens has already had to rotate a database password over exactly this leak on `/price/twap`, and the PR's own test pinned it (`expect(body.error).toContain('Connection terminated')`). The response is now a fixed `"Database unavailable"`, the detail goes to `req.log.error` where buildLogger pipes it through `redactSecrets`, and `statusErrorResponseSchema` gained `additionalProperties: false` so a `detail` field cannot be added back later. The test is inverted, and a second one asserts a connection-string-bearing error reaches neither the body nor the serialized response. 2. **Process health was hard-coded.** `const processHealth = 'healthy' as const` meant `health.process` and `process.status` could never be anything else, and the `degraded` branch of the published enum was unreachable — so the split this endpoint exists to make was cosmetic on one side. It now reads `isBootComplete()`: between `listen()` and `markBootComplete()` the port answers while not every ingester is running, which is a degraded process with perfectly fresh data. Covered by a test, and documented in the README next to the paging thresholds, pointing at `/ready` as the rollout gate. Also named the 300-second staleness threshold, since the README's Datadog/Prometheus/BetterStack examples and the openapi `degraded` contract all quote it and a monitor tuned to a different number is worse than none. 125 test files / 1,486 tests pass; tsc and build clean. Claude-Session: https://claude.ai/code/session_01USgemLt4Rnz4SGB1Srf3GB
|
Merged as Two fixes before it went in. 1. The 503 returned the Postgres driver's message on a public endpoint (blocking)} catch (err: any) {
return reply.status(503).send({
ok: false,
status: 'unhealthy',
error: err?.message || 'Database query failed',
pagingCondition: 'DATABASE_DOWN',
})
}
Lens has already had to rotate a database password over this exact shape of leak on What makes it worth flagging rather than just fixing quietly is that the test pinned the leak as the intended behaviour: expect(body.error).toContain('Connection terminated')A test asserting a leaked driver message is a test that will defend it against the next person who tries to remove it. I inverted it, and added a second case that feeds in a connection-string-bearing error and asserts none of The fix keeps the diagnostic, it just sends it to the right place: } catch (err: unknown) {
req.log.error({ err }, 'status: database query failed')
return reply.status(503).send({
ok: false,
status: 'unhealthy',
error: 'Database unavailable',
pagingCondition: 'DATABASE_DOWN',
})
}
Nothing is lost for the monitor: 2. Process health was a constantconst processHealth = 'healthy' as const
process:
type: string
enum: [healthy, degraded]— was unreachable. So "separates process health from data health" was true on the data side and decorative on the process side: It now reads a real signal: const processHealth = isBootComplete() ? ('healthy' as const) : ('degraded' as const)
One knock-on: I also pulled the 300-second threshold out into a named constant. It is a published number — the README monitoring examples quote Generated artifacts
125 test files / 1,486 tests pass. |
These duplicate work already on main through Divinity-Labs#533 (Divinity-Labs#273). This PR is for Divinity-Labs#275 only.
Closes #273
Summary of Changes
/statusinopenapi.yaml,openapi.json, andREADME.md.uptimeSeconds,memoryUsageMb,status) from data health (lastIndexedLedger,lastProcessedAt,ingestLagSeconds,isStale).status: "degraded"wheningestLagSeconds > 300but server process is healthy) without false alarm paging.503 Service UnavailablewithpagingCondition: "DATABASE_DOWN"only when critical infrastructure failures occur (e.g. Postgres disconnect), providing a clear paging threshold for uptime monitors.README.md.src/__tests__/statusContract.test.ts.